﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace SharpShare.Configuration {
    public class BytesTypeConverter : TypeConverter {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
            if (sourceType == typeof(string))
                return true;
            return base.CanConvertFrom(context, sourceType);
        }
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
            if (destinationType == typeof(string))
                return true;
            return base.CanConvertTo(context, destinationType);
        }
        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) {
            if (destinationType == typeof(string)) {
                double? parsed = value.AsDouble();
                if (!parsed.HasValue)
                    return null;

                double bytes = parsed ?? 0.0;

                if (bytes <= 0.0) {
                    return null;
                }

                string[] denominations = new[] { "bytes", "KB", "MB", "GB", "TB" };
                int index = 0;

                while (bytes >= 1024.0) {
                    if (index + 1 >= denominations.Length)
                        break;

                    bytes /= 1024.0;

                    index++;
                }

                string formatted = string.Format("{0:N2} {1}", bytes, denominations[index]);

                return formatted;
            }

            return base.ConvertTo(context, culture, value, destinationType);
        }
        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) {
            if (value is string) {
                if (string.IsNullOrWhiteSpace((string)value))
                    return null;

                StringBuilder digits = new StringBuilder();
                bool digitsDone = false;
                string denomination = string.Empty;

                foreach (char c in value.ToString()) {
                    if (!digitsDone) {
                        if (char.IsDigit(c) || c == '.') {
                            digits.Append(c);
                        } else if (c == ',') {

                        } else {
                            digitsDone = true;
                        }
                    }

                    if (digitsDone) {
                        denomination += c;
                    }
                }

                double? parsed = digits.AsDouble();
                if (!parsed.HasValue)
                    return null;

                double amount = parsed.Value;
                ulong factor;

                denomination = denomination.Trim().ToLower();

                switch (denomination) {
                    case "b":
                    case "":
                        factor = 0;
                        break;
                    case "kb":
                        factor = 1;
                        break;
                    case "mb":
                        factor = 2;
                        break;
                    case "gb":
                        factor = 3;
                        break;
                    case "tb":
                        factor = 4;
                        break;
                    default:
                        throw new FormatException(string.Format("Byte denomination '{0}' unrecognized.", denomination.ToUpper()));
                }

                double finalAmount = amount;

                for (ulong x = 0; x < factor; x++) {
                    finalAmount *= 1024.0;
                }

                return (ulong)finalAmount;
            }

            return base.ConvertFrom(context, culture, value);
        }
    }
}
